/*
 * @Author: zxc
 * @Date: 2021-01-24 14:42:43
 * @LastEditTime: 2021-01-24 16:06:37
 * @LastEditors: zxc
 * @Description: 函子Functor
 */
import _ from "lodash/fp"
class Container {
  constructor(value) {
    this._value = value
  }

  map(fn) {
    return new Container(fn(this._value))
  }
}

// console.log(new Container(5).map(x => x + 3).map(x => x ** 2))

class Container_2 {
  static of(value) {
    return new Container_2(value)
  }
  constructor(value) {
    this._value = value
  }
  map(fn) {
    return Container_2.of(fn(this._value))
  }
}
// console.log(
//   Container_2.of(5)
//     .map(x => x + 3)
//     .map(x => x ** 2)
// )

/**
 * @Author: zxc
 * @Date: 2021-01-24 15:14:28
 * @func MyBe函子
 */
class MyBe {
  constructor(value) {
    this._value = value
  }

  static of(value) {
    return new MyBe(value)
  }

  isNoting() {
    return !!this._value
  }

  map(fn) {
    return this.isNoting() ? MyBe.of(fn(this._value)) : MyBe.of(null)
  }
}

// console.log(MyBe.of("Hello world").map(x => x.toUpperCase()))
// console.log(MyBe.of(null).map(x => x.toUpperCase()))
// console.log(
//   MyBe.of("Hello world")
//     .map(x => x.toUpperCase())
//     .map(x => null)
//     .map(x => x.split(" "))
// )

/**
 * @Author: zxc
 * @Date: 2021-01-24 15:14:08
 * @func Eigher函子
 */
class Left {
  static of(value) {
    return new Left(value)
  }
  constructor(value) {
    this._value = value
  }
  map(fn) {
    return this
  }
}

class Right {
  static of(value) {
    return new Right(value)
  }
  constructor(value) {
    this._value = value
  }
  map(fn) {
    return Right.of(fn(this._value))
  }
}

let r1 = Right.of(12).map(x => x + 2)
let l1 = Left.of(12).map(x => x + 2)
// console.log(r1, l1)

function parseJSON(str) {
  try {
    return Right.of(JSON.parse(str))
  } catch (e) {
    return Left.of({
      error: e.message
    })
  }
}

let r = parseJSON(`{"name":"laotou"}`).map(x => x.name.toUpperCase())
// console.log(r)

/**
 * @Author: zxc
 * @Date: 2021-01-24 15:23:17
 * @func IO函子
 */

class IO {
  static of(value) {
    return new IO(function () {
      return value
    })
  }
  constructor(fn) {
    this._value = fn
  }
  map(fn) {
    return new IO(_.flowRight(fn, this._value))
  }
}
let Iotest = IO.of(window.location).map(x => x.origin)
// console.log(Iotest._value())

/**
 * @Author: zxc
 * @Date: 2021-01-24 15:32:59
 * @func task函子
 */
// see folktale.js
